// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.util.set;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import zombie.util.IntCollection;
import zombie.util.IntIterator;
import zombie.util.hash.DefaultIntHashFunction;
import zombie.util.hash.IntHashFunction;
import zombie.util.hash.Primes;
import zombie.util.util.Exceptions;

public class IntOpenHashSet extends AbstractIntSet implements IntSet, Cloneable, Serializable {
    private static final long serialVersionUID = 1L;
    private static final int GROWTH_POLICY_RELATIVE = 0;
    private static final int GROWTH_POLICY_ABSOLUTE = 1;
    private static final int DEFAULT_GROWTH_POLICY = 0;
    public static final double DEFAULT_GROWTH_FACTOR = 1.0;
    public static final int DEFAULT_GROWTH_CHUNK = 10;
    public static final int DEFAULT_CAPACITY = 11;
    public static final double DEFAULT_LOAD_FACTOR = 0.75;
    private IntHashFunction keyhash;
    private int size;
    private transient int[] data;
    private transient byte[] states;
    private static final byte EMPTY = 0;
    private static final byte OCCUPIED = 1;
    private static final byte REMOVED = 2;
    private transient int used;
    private int growthPolicy;
    private double growthFactor;
    private int growthChunk;
    private double loadFactor;
    private int expandAt;

    private IntOpenHashSet(IntHashFunction intHashFunction, int int0, int int2, double double0, int int1, double double1) {
        if (intHashFunction == null) {
            Exceptions.nullArgument("hash function");
        }

        if (int0 < 0) {
            Exceptions.negativeArgument("capacity", String.valueOf(int0));
        }

        if (double0 <= 0.0) {
            Exceptions.negativeOrZeroArgument("growthFactor", String.valueOf(double0));
        }

        if (int1 <= 0) {
            Exceptions.negativeOrZeroArgument("growthChunk", String.valueOf(int1));
        }

        if (double1 <= 0.0) {
            Exceptions.negativeOrZeroArgument("loadFactor", String.valueOf(double1));
        }

        this.keyhash = intHashFunction;
        int0 = Primes.nextPrime(int0);
        this.data = new int[int0];
        this.states = new byte[int0];
        this.size = 0;
        this.expandAt = (int)Math.round(double1 * (double)int0);
        this.used = 0;
        this.growthPolicy = int2;
        this.growthFactor = double0;
        this.growthChunk = int1;
        this.loadFactor = double1;
    }

    private IntOpenHashSet(int int0, int int1, double double0, int int2, double double1) {
        this(DefaultIntHashFunction.INSTANCE, int0, int1, double0, int2, double1);
    }

    public IntOpenHashSet() {
        this(11);
    }

    public IntOpenHashSet(IntCollection intCollection) {
        this();
        this.addAll(intCollection);
    }

    public IntOpenHashSet(int[] int1) {
        this();

        for (int int0 : int1) {
            this.add(int0);
        }
    }

    public IntOpenHashSet(int _int) {
        this(_int, 0, 1.0, 10, 0.75);
    }

    public IntOpenHashSet(double _double) {
        this(11, 0, 1.0, 10, _double);
    }

    public IntOpenHashSet(int _int, double _double) {
        this(_int, 0, 1.0, 10, _double);
    }

    public IntOpenHashSet(int _int, double double1, double double0) {
        this(_int, 0, double0, 10, double1);
    }

    public IntOpenHashSet(int int0, double _double, int int1) {
        this(int0, 1, 1.0, int1, _double);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction) {
        this(intHashFunction, 11, 0, 1.0, 10, 0.75);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction, int _int) {
        this(intHashFunction, _int, 0, 1.0, 10, 0.75);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction, double _double) {
        this(intHashFunction, 11, 0, 1.0, 10, _double);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction, int _int, double _double) {
        this(intHashFunction, _int, 0, 1.0, 10, _double);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction, int _int, double double1, double double0) {
        this(intHashFunction, _int, 0, double0, 10, double1);
    }

    public IntOpenHashSet(IntHashFunction intHashFunction, int int0, double _double, int int1) {
        this(intHashFunction, int0, 1, 1.0, int1, _double);
    }

    private void ensureCapacity(int int0) {
        if (int0 >= this.expandAt) {
            int int1;
            if (this.growthPolicy == 0) {
                int1 = (int)((double)this.data.length * (1.0 + this.growthFactor));
            } else {
                int1 = this.data.length + this.growthChunk;
            }

            if ((double)int1 * this.loadFactor < (double)int0) {
                int1 = (int)Math.round((double)int0 / this.loadFactor);
            }

            int1 = Primes.nextPrime(int1);
            this.expandAt = (int)Math.round(this.loadFactor * (double)int1);
            int[] int2 = new int[int1];
            byte[] _byte = new byte[int1];
            this.used = 0;

            for (int int3 = 0; int3 < this.data.length; int3++) {
                if (this.states[int3] == 1) {
                    this.used++;
                    int int4 = this.data[int3];
                    int int5 = Math.abs(this.keyhash.hash(int4));
                    int int6 = int5 % int1;
                    if (_byte[int6] == 1) {
                        int int7 = 1 + int5 % (int1 - 2);

                        do {
                            int6 -= int7;
                            if (int6 < 0) {
                                int6 += int1;
                            }
                        } while (_byte[int6] != 0);
                    }

                    _byte[int6] = 1;
                    int2[int6] = int4;
                }
            }

            this.data = int2;
            this.states = _byte;
        }
    }

    @Override
    public boolean add(int v) {
        this.ensureCapacity(this.used + 1);
        int int0 = Math.abs(this.keyhash.hash(v));
        int int1 = int0 % this.data.length;
        if (this.states[int1] == 1) {
            if (this.data[int1] == v) {
                return false;
            }

            int int2 = 1 + int0 % (this.data.length - 2);

            while (true) {
                int1 -= int2;
                if (int1 < 0) {
                    int1 += this.data.length;
                }

                if (this.states[int1] == 0 || this.states[int1] == 2) {
                    break;
                }

                if (this.states[int1] == 1 && this.data[int1] == v) {
                    return false;
                }
            }
        }

        if (this.states[int1] == 0) {
            this.used++;
        }

        this.states[int1] = 1;
        this.data[int1] = v;
        this.size++;
        return true;
    }

    @Override
    public IntIterator iterator() {
        return new IntIterator() {
            int nextEntry = this.nextEntry(0);
            int lastEntry = -1;

            int nextEntry(int _int) {
                while (_int < IntOpenHashSet.this.data.length && IntOpenHashSet.this.states[_int] != 1) {
                    _int++;
                }

                return _int;
            }

            @Override
            public boolean hasNext() {
                return this.nextEntry < IntOpenHashSet.this.data.length;
            }

            @Override
            public int next() {
                if (!this.hasNext()) {
                    Exceptions.endOfIterator();
                }

                this.lastEntry = this.nextEntry;
                this.nextEntry = this.nextEntry(this.nextEntry + 1);
                return IntOpenHashSet.this.data[this.lastEntry];
            }

            @Override
            public void remove() {
                if (this.lastEntry == -1) {
                    Exceptions.noElementToRemove();
                }

                IntOpenHashSet.this.states[this.lastEntry] = 2;
                IntOpenHashSet.this.size--;
                this.lastEntry = -1;
            }
        };
    }

    @Override
    public void trimToSize() {
    }

    public Object clone() {
        try {
            IntOpenHashSet intOpenHashSet0 = (IntOpenHashSet)super.clone();
            intOpenHashSet0.data = new int[this.data.length];
            System.arraycopy(this.data, 0, intOpenHashSet0.data, 0, this.data.length);
            intOpenHashSet0.states = new byte[this.data.length];
            System.arraycopy(this.states, 0, intOpenHashSet0.states, 0, this.states.length);
            return intOpenHashSet0;
        } catch (CloneNotSupportedException cloneNotSupportedException) {
            Exceptions.cloning();
            throw new RuntimeException();
        }
    }

    @Override
    public int size() {
        return this.size;
    }

    @Override
    public void clear() {
        this.size = 0;
        this.used = 0;
        Arrays.fill(this.states, (byte)0);
    }

    @Override
    public boolean contains(int v) {
        int int0 = Math.abs(this.keyhash.hash(v));
        int int1 = int0 % this.data.length;
        if (this.states[int1] == 0) {
            return false;
        } else if (this.states[int1] == 1 && this.data[int1] == v) {
            return true;
        } else {
            int int2 = 1 + int0 % (this.data.length - 2);

            do {
                int1 -= int2;
                if (int1 < 0) {
                    int1 += this.data.length;
                }

                if (this.states[int1] == 0) {
                    return false;
                }
            } while (this.states[int1] != 1 || this.data[int1] != v);

            return true;
        }
    }

    @Override
    public int hashCode() {
        int int0 = 0;

        for (int int1 = 0; int1 < this.data.length; int1++) {
            if (this.states[int1] == 1) {
                int0 += this.data[int1];
            }
        }

        return int0;
    }

    @Override
    public boolean remove(int v) {
        int int0 = Math.abs(this.keyhash.hash(v));
        int int1 = int0 % this.data.length;
        if (this.states[int1] == 0) {
            return false;
        } else if (this.states[int1] == 1 && this.data[int1] == v) {
            this.states[int1] = 2;
            this.size--;
            return true;
        } else {
            int int2 = 1 + int0 % (this.data.length - 2);

            do {
                int1 -= int2;
                if (int1 < 0) {
                    int1 += this.data.length;
                }

                if (this.states[int1] == 0) {
                    return false;
                }
            } while (this.states[int1] != 1 || this.data[int1] != v);

            this.states[int1] = 2;
            this.size--;
            return true;
        }
    }

    @Override
    public int[] toArray(int[] int0) {
        if (int0 == null || int0.length < this.size) {
            int0 = new int[this.size];
        }

        int int1 = 0;

        for (int int2 = 0; int2 < this.data.length; int2++) {
            if (this.states[int2] == 1) {
                int0[int1++] = this.data[int2];
            }
        }

        return int0;
    }

    private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
        objectOutputStream.defaultWriteObject();
        objectOutputStream.writeInt(this.data.length);
        IntIterator intIterator = this.iterator();

        while (intIterator.hasNext()) {
            int _int = intIterator.next();
            objectOutputStream.writeInt(_int);
        }
    }

    private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
        objectInputStream.defaultReadObject();
        this.data = new int[objectInputStream.readInt()];
        this.states = new byte[this.data.length];
        this.used = this.size;

        for (int int0 = 0; int0 < this.size; int0++) {
            int int1 = objectInputStream.readInt();
            int int2 = Math.abs(this.keyhash.hash(int1));
            int int3 = int2 % this.data.length;
            if (this.states[int3] == 1) {
                int int4 = 1 + int2 % (this.data.length - 2);

                do {
                    int3 -= int4;
                    if (int3 < 0) {
                        int3 += this.data.length;
                    }
                } while (this.states[int3] != 0);
            }

            this.states[int3] = 1;
            this.data[int3] = int1;
        }
    }
}
